//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_LIBC_CMATH_H
#define _UXS_LIBC_CMATH_H

#pragma once

#include "c_defs.h"


extern "C" {

#	ifdef COMPILER_MSVC
		static const int RAND_MAX  = 0x7fff;

		int    __CDECL rand(void);
#	endif

#	ifdef COMPILER_GCC
		static const int RAND_MAX = 0x7fffffff;
		
		extern long lrand48(void);

		static __inline__ int rand(void) {
			return (int)lrand48();
		}
#	endif

/* Function prototypes */

#if     !defined(__assembler)   /* Protect from assembler */
        int     __CDECL abs(int _X);
        long    __CDECL labs(long _X);
        __INT64 __CDECL llabs(__INT64 _X);

        double  __CDECL acos(double _X);
        double  __CDECL asin(double _X);
        double  __CDECL atan(double _X);
        double  __CDECL atan2(double _Y, double _X);

        double  __CDECL cos(double _X);
        double  __CDECL cosh(double _X);
        double  __CDECL exp(double _X);
_CRT_JIT_INTRINSIC double  __CDECL fabs(double _X);
        double  __CDECL fmod(double _X, double _Y);
        double  __CDECL log(double _X);
        double  __CDECL log10(double _X);
        double  __CDECL pow(double _X, double _Y);
        double  __CDECL sin(double _X);
        double  __CDECL sinh(double _X);
        double  __CDECL tan(double _X);
        double  __CDECL tanh(double _X);
        double  __CDECL sqrt(double _X);
		double  __CDECL atof(const char *_String);

		//double  __CDECL _cabs(struct _complex _Complex_value);
		double  __CDECL ceil(double _X);
		double  __CDECL floor(double _X);
		double  __CDECL frexp(double _X, int * _Y);
		double  __CDECL ldexp(double _X, int _Y);

		double  __CDECL modf(double _X, double * _Y);

#if defined(_M_IX86)
int     __CDECL _set_SSE2_enable(int _Flag);
#endif

#if defined(_M_IA64)

/* ANSI C, 4.5 Mathematics        */

/* 4.5.2 Trigonometric functions */

float  __CDECL acosf( float _X);
float  __CDECL asinf( float _X);
float  __CDECL atanf( float _X);
float  __CDECL atan2f( float  _Y, float  _X);
float  __CDECL cosf( float _X);
float  __CDECL sinf( float _X);
float  __CDECL tanf( float _X);

/* 4.5.3 Hyperbolic functions */
float  __CDECL coshf( float _X);
float  __CDECL sinhf( float _X);
float  __CDECL tanhf( float _X);

/* 4.5.4 Exponential and logarithmic functions */
float  __CDECL expf( float  _X);
float  __CDECL logf( float  _X);
float  __CDECL log10f( float  _X);
float  __CDECL modff( float  _X, float*  _Y);

/* 4.5.5 Power functions */
float  __CDECL powf( float _Base, float _Exp);
float  __CDECL sqrtf( float  _X);

/* 4.5.6 Nearest integer, absolute value, and remainder functions */
float  __CDECL ceilf( float  _X);
_CRT_JIT_INTRINSIC  float  __CDECL fabsf( float  _X);
float  __CDECL floorf( float  _X);
float  __CDECL fmodf( float _X, float _Y);

float  __CDECL ldexpf(float _X, int _Y);

#endif /* _M_IA64 */

#if defined(_M_AMD64)

/* ANSI C, 4.5 Mathematics        */

/* 4.5.2 Trigonometric functions */

float  __CDECL acosf( float _X);
float  __CDECL asinf( float _X);
float  __CDECL atanf( float _X);
float  __CDECL atan2f( float  _Y, float  _X);
float  __CDECL cosf( float _X);
float  __CDECL sinf( float _X);
float  __CDECL tanf( float _X);

/* 4.5.3 Hyperbolic functions */
float  __CDECL coshf( float _X);
float  __CDECL sinhf( float _X);
float  __CDECL tanhf( float _X);

/* 4.5.4 Exponential and logarithmic functions */
float  __CDECL expf( float  _X);
float  __CDECL logf( float  _X);
float  __CDECL log10f( float  _X);
float  __CDECL modff( float  _X, float*  _Y);

/* 4.5.5 Power functions */
float  __CDECL powf( float _X, float _Y);
float  __CDECL sqrtf( float  _X);

/* 4.5.6 Nearest integer, absolute value, and remainder functions */
float  __CDECL ceilf( float  _X);
float  __CDECL floorf( float  _X);
float  __CDECL fmodf( float  _X, float _Y);

#endif /* _M_AMD64 */


/* Macros defining long double functions to be their double counterparts
 * (long double is synonymous with double in this implementation).
 */

inline long double acosl(long double _X)
        {return (acos((double)_X)); }
inline long double asinl(long double _X)
        {return (asin((double)_X)); }
inline long double atanl(long double _X)
        {return (atan((double)_X)); }
inline long double atan2l(long double _Y, long double _X)
        {return (atan2((double)_Y, (double)_X)); }
inline long double ceill(long double _X)
        {return (ceil((double)_X)); }
inline long double cosl(long double _X)
        {return (cos((double)_X)); }
inline long double coshl(long double _X)
        {return (cosh((double)_X)); }
inline long double expl(long double _X)
        {return (exp((double)_X)); }
inline long double fabsl(long double _X)
        {return (fabs((double)_X)); }
inline long double floorl(long double _X)
        {return (floor((double)_X)); }
inline long double fmodl(long double _X, long double _Y)
        {return (fmod((double)_X, (double)_Y)); }
inline long double frexpl(long double _X, int *_Y)
        {return (frexp((double)_X, _Y)); }
inline long double ldexpl(long double _X, int _Y)
        {return (ldexp((double)_X, _Y)); }
inline long double logl(long double _X)
        {return (log((double)_X)); }
inline long double log10l(long double _X)
        {return (log10((double)_X)); }
inline long double modfl(long double _X, long double *_Y)
        {double _Di, _Df = modf((double)_X, &_Di);
        *_Y = (long double)_Di;
        return (_Df); }
inline long double powl(long double _X, long double _Y)
        {return (pow((double)_X, (double)_Y)); }
inline long double sinl(long double _X)
        {return (sin((double)_X)); }
inline long double sinhl(long double _X)
        {return (sinh((double)_X)); }
inline long double sqrtl(long double _X)
        {return (sqrt((double)_X)); }
#ifndef _M_IA64
inline long double tanl(long double _X)
        {return (tan((double)_X)); }
#else
long double __CDECL tanl(long double _X);
#endif

inline long double tanhl(long double _X)
        {return (tanh((double)_X)); }

inline float frexpf(float _X, int *_Y)
        {return ((float)frexp((double)_X, _Y)); }

#if     !defined(_M_IA64) 
inline float fabsf(float _X)
        {return ((float)fabs((double)_X)); }
inline float ldexpf(float _X, int _Y)
        {return ((float)ldexp((double)_X, _Y)); }
#if     !defined(_M_AMD64)
inline float acosf(float _X)
        {return ((float)acos((double)_X)); }
inline float asinf(float _X)
        {return ((float)asin((double)_X)); }
inline float atanf(float _X)
        {return ((float)atan((double)_X)); }
inline float atan2f(float _Y, float _X)
        {return ((float)atan2((double)_Y, (double)_X)); }
inline float ceilf(float _X)
        {return ((float)ceil((double)_X)); }
inline float cosf(float _X)
        {return ((float)cos((double)_X)); }
inline float coshf(float _X)
        {return ((float)cosh((double)_X)); }
inline float expf(float _X)
        {return ((float)exp((double)_X)); }
inline float floorf(float _X)
        {return ((float)floor((double)_X)); }
inline float fmodf(float _X, float _Y)
        {return ((float)fmod((double)_X, (double)_Y)); }
inline float logf(float _X)
        {return ((float)log((double)_X)); }
inline float log10f(float _X)
        {return ((float)log10((double)_X)); }
inline float modff(float _X, float *_Y)
        { double _Di, _Df = modf((double)_X, &_Di);
        *_Y = (float)_Di;
        return ((float)_Df); }
inline float powf(float _X, float _Y)
        {return ((float)pow((double)_X, (double)_Y)); }
inline float sinf(float _X)
        {return ((float)sin((double)_X)); }
inline float sinhf(float _X)
        {return ((float)sinh((double)_X)); }
inline float sqrtf(float _X)
        {return ((float)sqrt((double)_X)); }
inline float tanf(float _X)
        {return ((float)tan((double)_X)); }
inline float tanhf(float _X)
        {return ((float)tanh((double)_X)); }
#endif  /* !defined(_M_AMD64) */
#endif  /* !defined(_M_IA64) */
#endif  /* __assembler */

#if     !__STDC__

/* Non-ANSI names for compatibility */

#ifndef __assembler /* Protect from assembler */

#if !defined(_M_CEE_PURE)
extern double HUGE;
#else
    const double HUGE = _HUGE;
#endif /* !defined(_M_CEE_PURE) */

#endif  /* __assembler */

#endif  /* __STDC__ */

}	/* extern "C" */

extern "C++" {

template<class _Ty> inline
        _Ty _Pow_int(_Ty _X, int _Y)
        {unsigned int _N;
        if (_Y >= 0)
                _N = (unsigned int)_Y;
        else
                _N = (unsigned int)(-_Y);
        for (_Ty _Z = _Ty(1); ; _X *= _X)
                {if ((_N & 1) != 0)
                        _Z *= _X;
                if ((_N >>= 1) == 0)
                        return (_Y < 0 ? _Ty(1) / _Z : _Z); }}

inline double __CDECL abs(double _X)
        {return (fabs(_X)); }
inline double __CDECL pow(double _X, int _Y)
        {return (_Pow_int(_X, _Y)); }
inline float __CDECL abs(float _X)
        {return (fabsf(_X)); }
inline float __CDECL acos(float _X)
        {return (acosf(_X)); }
inline float __CDECL asin(float _X)
        {return (asinf(_X)); }
inline float __CDECL atan(float _X)
        {return (atanf(_X)); }
inline float __CDECL atan2(float _Y, float _X)
        {return (atan2f(_Y, _X)); }
inline float __CDECL ceil(float _X)
        {return (ceilf(_X)); }
inline float __CDECL cos(float _X)
        {return (cosf(_X)); }
inline float __CDECL cosh(float _X)
        {return (coshf(_X)); }
inline float __CDECL exp(float _X)
        {return (expf(_X)); }
inline float __CDECL fabs(float _X)
        {return (fabsf(_X)); }
inline float __CDECL floor(float _X)
        {return (floorf(_X)); }
inline float __CDECL fmod(float _X, float _Y)
        {return (fmodf(_X, _Y)); }
inline float __CDECL frexp(float _X, int * _Y)
        {return (frexpf(_X, _Y)); }
inline float __CDECL ldexp(float _X, int _Y)
        {return (ldexpf(_X, _Y)); }
inline float __CDECL log(float _X)
        {return (logf(_X)); }
inline float __CDECL log10(float _X)
        {return (log10f(_X)); }
inline float __CDECL modf(float _X, float * _Y)
        {return (modff(_X, _Y)); }
inline float __CDECL pow(float _X, float _Y)
        {return (powf(_X, _Y)); }
inline float __CDECL pow(float _X, int _Y)
        {return (_Pow_int(_X, _Y)); }
inline float __CDECL sin(float _X)
        {return (sinf(_X)); }
inline float __CDECL sinh(float _X)
        {return (sinhf(_X)); }
inline float __CDECL sqrt(float _X)
        {return (sqrtf(_X)); }
inline float __CDECL tan(float _X)
        {return (tanf(_X)); }
inline float __CDECL tanh(float _X)
        {return (tanhf(_X)); }
inline long double __CDECL abs(long double _X)
        {return (fabsl(_X)); }
inline long double __CDECL acos(long double _X)
        {return (acosl(_X)); }
inline long double __CDECL asin(long double _X)
        {return (asinl(_X)); }
inline long double __CDECL atan(long double _X)
        {return (atanl(_X)); }
inline long double __CDECL atan2(long double _Y, long double _X)
        {return (atan2l(_Y, _X)); }
inline long double __CDECL ceil(long double _X)
        {return (ceill(_X)); }
inline long double __CDECL cos(long double _X)
        {return (cosl(_X)); }
inline long double __CDECL cosh(long double _X)
        {return (coshl(_X)); }
inline long double __CDECL exp(long double _X)
        {return (expl(_X)); }
inline long double __CDECL fabs(long double _X)
        {return (fabsl(_X)); }
inline long double __CDECL floor(long double _X)
        {return (floorl(_X)); }
inline long double __CDECL fmod(long double _X, long double _Y)
        {return (fmodl(_X, _Y)); }
inline long double __CDECL frexp(long double _X, int * _Y)
        {return (frexpl(_X, _Y)); }
inline long double __CDECL ldexp(long double _X, int _Y)
        {return (ldexpl(_X, _Y)); }
inline long double __CDECL log(long double _X)
        {return (logl(_X)); }
inline long double __CDECL log10(long double _X)
        {return (log10l(_X)); }
inline long double __CDECL modf(long double _X, long double * _Y)
        {return (modfl(_X, _Y)); }
inline long double __CDECL pow(long double _X, long double _Y)
        {return (powl(_X, _Y)); }
inline long double __CDECL pow(long double _X, int _Y)
        {return (_Pow_int(_X, _Y)); }
inline long double __CDECL sin(long double _X)
        {return (sinl(_X)); }
inline long double __CDECL sinh(long double _X)
        {return (sinhl(_X)); }
inline long double __CDECL sqrt(long double _X)
        {return (sqrtl(_X)); }
inline long double __CDECL tan(long double _X)
        {return (tanl(_X)); }
inline long double __CDECL tanh(long double _X)
        {return (tanhl(_X)); }

}	// extern "C++"

#endif	// _UXS_LIBC_CMATH_H
